@use 'sass:map';
@use '@material/animation' as mdc-animation;
@use '@material/switch/switch' as mdc-switch;
@use '@material/switch/switch-theme' as mdc-switch-theme;
@use '@material/ripple' as mdc-ripple;
@use '../core/style/layout-common';
@use '@material/theme/custom-properties' as mdc-custom-properties;
@use '../core/tokens/m2/mat/switch' as m2-mat-switch;
@use '../core/tokens/m2/mdc/switch' as m2-mdc-switch;
@use '../core/tokens/token-utils';

@include mdc-custom-properties.configure($emit-fallback-values: false, $emit-fallback-vars: false) {
  $mdc-switch-token-slots: m2-mdc-switch.get-token-slots();

  // Add the MDC switch static styles.
  @include mdc-switch.static-styles-without-ripple();

  // TODO(wagnermaciel): Use our custom token system to emit this css rule.
  .mat-mdc-slide-toggle .mdc-switch--disabled + label {
    color: var(--mdc-switch-disabled-label-text-color);
  }

  .mdc-switch {
    // Add the official slots for the MDC switch
    @include mdc-switch-theme.theme-styles($mdc-switch-token-slots);

    // The tokens are outputting handle-elevation and disabled-handle-elevation
    // as the values for box-shadow. Rather the value that should be displayed
    // is calculated using the tokens for elevation and the handle-shadow-color
    // within theme-styles and is stored in new variables that end in -shadow.

    // TODO(amysorto): remove these overrides once MDC emits correct value for
    // box-shadow.

    // Override box-shadow with correct values.
    &:enabled .mdc-switch__shadow {
      box-shadow: var(--mdc-switch-handle-elevation-shadow);
    }

    &:disabled .mdc-switch__shadow {
      box-shadow: var(--mdc-switch-disabled-handle-elevation-shadow);
    }
  }
}

.mat-mdc-slide-toggle {
  display: inline-block;
  -webkit-tap-highlight-color: transparent;

  // Remove the native outline since we use the ripple for focus indication.
  outline: 0;

  // The ripple needs extra specificity so the base ripple styling doesn't override its `position`.
  .mat-mdc-slide-toggle-ripple, #{mdc-switch.$ripple-target}::after {
    @include layout-common.fill();
    border-radius: 50%;
    // Disable pointer events for the ripple container so that it doesn't eat the mouse events meant
    // for the input. Pointer events can be safely disabled because the ripple trigger element is
    // the host element.
    pointer-events: none;
    // Fixes the ripples not clipping to the border radius on Safari. Uses `:not(:empty)`
    // in order to avoid creating extra layers when there aren't any ripples.
    &:not(:empty) {
      transform: translateZ(0);
    }
  }

  #{mdc-switch.$ripple-target}::after {
    content: '';
    opacity: 0;
  }

  .mdc-switch:hover #{mdc-switch.$ripple-target}::after {
    opacity: map.get(mdc-ripple.$dark-ink-opacities, hover);
    transition: mdc-animation.enter(opacity, 75ms);
  }

  // Needs a little more specificity so the :hover styles don't override it.
  &.mat-mdc-slide-toggle-focused {
    .mdc-switch #{mdc-switch.$ripple-target}::after {
      opacity: map.get(mdc-ripple.$dark-ink-opacities, focus);
    }

    // For slide-toggles render the focus indicator when we know
    // the hidden input is focused (slightly different for each control).
    .mat-mdc-focus-indicator::before {
      content: '';
    }
  }

  // We use an Angular Material ripple rather than an MDC ripple due to size concerns, so we need to
  // style it appropriately.
  .mat-ripple-element {
    opacity: map.get(mdc-ripple.$dark-ink-opacities, press);
  }

  // Slide-toggle components have to set `border-radius: 50%` in order to support density scaling
  // which will clip a square focus indicator so we have to turn it into a circle.
  .mat-mdc-focus-indicator::before {
    border-radius: 50%;
  }

  &._mat-animation-noopable {
    .mdc-switch__handle-track,
    .mdc-elevation-overlay,
    .mdc-switch__icon,
    .mdc-switch__handle::before,
    .mdc-switch__handle::after,
    .mdc-switch__track::before,
    .mdc-switch__track::after {
      transition: none;
    }
  }

  // If our slide-toggle is enabled the cursor on label should appear as a pointer.
  .mdc-switch:enabled + .mdc-label {
    cursor: pointer;
  }
}

// Used for M3 animations. Does not affect the M2 slide-toggle
// because the width and height are static, and the margin is unused.
.mdc-switch__handle {
  transition:
    width 75ms cubic-bezier(0.4, 0, 0.2, 1),
    height 75ms cubic-bezier(0.4, 0, 0.2, 1),
    margin 75ms cubic-bezier(0.4, 0, 0.2, 1);
}

// The hidden and visible track represent whichever track is visible or
// hidden in the ui. This could be the .mdc-switch__track :before or
// :after depending on whether the switch is selected or unselected.
//
// The m2 slide-toggle uses transforms to hide & show the tracks while
// the m3 slide-toggle uses opacity.

@include token-utils.use-tokens(m2-mat-switch.$prefix, m2-mat-switch.get-token-slots()) {
  .mdc-switch--selected .mdc-switch__track {
    &::before {
      @include token-utils.create-token-slot(opacity, hidden-track-opacity);
      @include token-utils.create-token-slot(transition, hidden-track-transition);
    }
    &::after {
      @include token-utils.create-token-slot(opacity, visible-track-opacity);
      @include token-utils.create-token-slot(transition, visible-track-transition);
    }
  }

  .mdc-switch--unselected .mdc-switch__track {
    &::before {
      @include token-utils.create-token-slot(opacity, visible-track-opacity);
      @include token-utils.create-token-slot(transition, visible-track-transition);
    }
    &::after {
      @include token-utils.create-token-slot(opacity, hidden-track-opacity);
      @include token-utils.create-token-slot(transition, hidden-track-transition);
    }
  }
}

@include token-utils.use-tokens(m2-mat-switch.$prefix, m2-mat-switch.get-token-slots()) {
  .mat-mdc-slide-toggle {
    .mdc-switch--unselected .mdc-switch__handle {
      @include token-utils.create-token-slot(width, unselected-handle-size);
      @include token-utils.create-token-slot(height, unselected-handle-size);
    }

    .mdc-switch--selected .mdc-switch__handle {
      @include token-utils.create-token-slot(width, selected-handle-size);
      @include token-utils.create-token-slot(height, selected-handle-size);
    }

    .mdc-switch__handle:has(.mdc-switch__icons) {
      @include token-utils.create-token-slot(width, with-icon-handle-size);
      @include token-utils.create-token-slot(height, with-icon-handle-size);
    }

    &:active .mdc-switch:not(.mdc-switch--disabled) .mdc-switch__handle {
      @include token-utils.create-token-slot(width, pressed-handle-size);
      @include token-utils.create-token-slot(height, pressed-handle-size);
    }
  }
}

@include token-utils.use-tokens(m2-mat-switch.$prefix, m2-mat-switch.get-token-slots()) {
  .mat-mdc-slide-toggle {
    .mdc-switch--selected .mdc-switch__handle {
      @include token-utils.create-token-slot(margin, selected-handle-horizontal-margin);

      &:has(.mdc-switch__icons) {
        @include token-utils.create-token-slot(margin, selected-with-icon-handle-horizontal-margin);
      }
    }

    .mdc-switch--unselected .mdc-switch__handle {
      @include token-utils.create-token-slot(margin, unselected-handle-horizontal-margin);

      &:has(.mdc-switch__icons) {
        @include token-utils.create-token-slot(
          margin,
          unselected-with-icon-handle-horizontal-margin,
        );
      }
    }

    &:active .mdc-switch--selected:not(.mdc-switch--disabled) .mdc-switch__handle {
      @include token-utils.create-token-slot(margin, selected-pressed-handle-horizontal-margin);
    }

    &:active .mdc-switch--unselected:not(.mdc-switch--disabled) .mdc-switch__handle {
      @include token-utils.create-token-slot(margin, unselected-pressed-handle-horizontal-margin);
    }
  }
}

@include token-utils.use-tokens(m2-mat-switch.$prefix, m2-mat-switch.get-token-slots()) {
  .mdc-switch__track::after,
  .mdc-switch__track::before {
    @include token-utils.create-token-slot(border-width, track-outline-width);
    @include token-utils.create-token-slot(border-color, track-outline-color);
  }

  .mdc-switch--selected .mdc-switch__track::after,
  .mdc-switch--selected .mdc-switch__track::before {
    @include token-utils.create-token-slot(border-width, selected-track-outline-width);
    @include token-utils.create-token-slot(border-color, selected-track-outline-color);
  }

  .mdc-switch--disabled .mdc-switch__track::after,
  .mdc-switch--disabled .mdc-switch__track::before {
    @include token-utils.create-token-slot(border-width, disabled-unselected-track-outline-width);
    @include token-utils.create-token-slot(border-color, disabled-unselected-track-outline-color);
  }
}

@include token-utils.use-tokens(m2-mat-switch.$prefix, m2-mat-switch.get-token-slots()) {
  .mdc-switch--disabled.mdc-switch--selected .mdc-switch__handle::after {
    @include token-utils.create-token-slot(opacity, disabled-selected-handle-opacity);
  }

  .mdc-switch--disabled.mdc-switch--unselected .mdc-switch__handle::after {
    @include token-utils.create-token-slot(opacity, disabled-unselected-handle-opacity);
  }
}
